# -*- coding: utf-8 -*-
import os, stat
from os.path import join, isfile, abspath, dirname
from time import mktime
from datetime import datetime, timedelta
from mimetypes import guess_type
from werkzeug.utils import cached_property
from werkzeug.wrappers import Request, BaseResponse, Response
from werkzeug.exceptions import NotFound, MethodNotAllowed
from werkzeug.contrib.securecookie import SecureCookie
from werkzeug._internal import _patch_wrapper
from accost.paginator import Paginator, InvalidPage
try:
    from simplejson import dumps
except ImportError:
    from json import dumps
SESSION_USER_KEY = '_auth_user_id'
_current_path = abspath(dirname(__file__))


class AccostRequest(Request):
    @property
    def kwargs(self):
        return self.environ["accost.kwargs"]

    @cached_property
    def client_session(self):
        secret_key = self.environ["accost.secret_key"]
        return SecureCookie.load_cookie(self, secret_key=secret_key)

    @cached_property
    def session(self):
        session_store = self.environ["accost.session_store"]
        sid = self.cookies.get('session_id')
        if sid is None:
            return session_store.new()
        else:
            return session_store.get(sid)

    @cached_property
    def user_id(self):
        return self.client_session.get(SESSION_USER_KEY)

    def save_session(self, session_store, response):
        if self.session.should_save:
            session_store.save(self.session)
            try:
                response.set_cookie('session_id', self.session.sid)
            except AttributeError:
                pass

    def logout(self):
        try:
            del self.session[SESSION_USER_KEY]
        except KeyError:
            pass
        try:
            del self.client_session[SESSION_USER_KEY]
        except KeyError:
            pass

    def finish(self, response):
        session_store = self.environ["accost.session_store"]
        # save session
        self.save_session(session_store, response)
        # save client session
        self.client_session.save_cookie(response)
        self.client_session.modified = False

    @classmethod
    def app(cls, f):
        def wsgi_app(environ, start_response):
            request = cls(environ)
            response = f(request)
            request.finish(response)
            assert isinstance(response, BaseResponse)
            return response(environ, start_response)
        return _patch_wrapper(f, wsgi_app)

    @staticmethod
    def staticApp(static_dir):
        def _serve_static(request):
            path = request.kwargs.get("path")
            if path is None:
                filename = static_dir
            else:
                filename = join(static_dir, path)
            if not isfile(filename):
                raise NotFound
            type, encoding = guess_type(filename)
            type = type or 'application/octet-stream'
            real_mtime = os.stat(filename)[stat.ST_MTIME]
            if request.if_modified_since:
                ask_mtime = int(mktime(request.if_modified_since.timetuple()))
                if ask_mtime >= real_mtime:
                    return Response(status=304)
            response = Response(mimetype=type)
            now = datetime.now()
            response.last_modified = datetime.fromtimestamp(real_mtime)
            response.expires = now + timedelta(seconds=3600)
            response.cache_control.max_age = 3600
            response.response = open(filename, 'rb')
            return response
        return AccostRequest.app(_serve_static)

    @staticmethod
    def captchaApp():
        def _internal(request):
            import captchaimage
            import Image, ImageDraw
            #text = md5(str(datetime.now())).hexdigest()[:4]
            text = "%04d"%randint(0, 9999)
            request.client_session["checkcode"] = text.lower()
            size_x = 30
            size_y = 40
            image_data = captchaimage.create_image(
                join(_current_path, "roughage.ttf"), size_x, size_y, text
            )
            image = Image.fromstring(
                    "L", (len(image_data) / size_y, size_y), image_data
            )
            buf = StringIO()
            image.save(buf, "jpeg")
            return Response(buf.getvalue(), mimetype="image/jpeg",
                    headers=[('Expires', '0'), ('Pragma', 'no-cache')])
        return AccostRequest.app(_internal)

    @classmethod
    def rest(cls):
        def _internal(request):
            if request.method == 'GET':
                return self.get()
            elif request.method == 'POST':
                return self.post()
            elif request.method == 'HEAD':
                return self.head()
            elif request.method == 'OPTIONS':
                return self.options()
            elif request.method == 'PUT':
                return self.put()
            elif request.method == 'DELETE':
                return self.delete()
            elif request.method == 'TRACE':
                return self.trace()
            else:
                raise MethodNotAllowed
        return cls.app(_internal)

    def get(self):
        raise MethodNotAllowed

    def post(self):
        raise MethodNotAllowed

    def head(self):
        raise MethodNotAllowed

    def options(self):
        raise MethodNotAllowed

    def put(self):
        raise MethodNotAllowed

    def delete(self):
        raise MethodNotAllowed

    def trace(self):
        raise MethodNotAllowed

    def page(self, object_list, per_page, **kw):
        paginator = Paginator(object_list, per_page, **kw)
        page_num = self.args.get("page", u"1")
        if page_num == u"last":
            page_num = paginator.page_range[-1]
        try:
            page_num = paginator.validate_number(page_num)
            page = paginator.page(page_num)
        except InvalidPage:
            raise NotFound
        return page


def JsonResponse(obj):
    return Response(dumps(obj), content_type="application/json")


def JsonMessage(result, message):
    return Response(dumps({"result": result, "message": message}),
            content_type="application/json")
